/**
 * Copyright (c) 2011 eelpo.com
 * All rights reserved.
 */
package com.eelpo.common.security;

import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;

import com.eelpo.common.encoder.BASE64DecoderStream;
import com.eelpo.common.encoder.BASE64EncoderStream;
import com.eelpo.common.util.BlankUtils;
import com.eelpo.common.util.StringUtils;

/**
 * 功能描述：使用哈希算法对密码进行哈希计算,哈希算法推荐使用SHA-1,MD5。
 * 
 * 对密码参合随机盐进行简单的64位加码解码
 * <p>
 * 版权所有：广州市艾尔博科技有限公司
 * <p>
 * 未经本公司许可，不得以任何方式复制或使用本程序任何部分
 * 
 * @author <a href="mailto:Brian@eelpo.com">汪洪州</a>
 * @since 1.0
 */
public class PasswordEncryptor {

	/**
	 * <p>
	 * 方法用途和描述：对密码进行哈希计算获取密码的信息摘要
	 * </p>
	 * 
	 * @param password
	 *            ：需要计算信息摘要的密码
	 * @param algorithm
	 *            ：哈希算法
	 * @return 返回信息摘要
	 */
	public static String digest(String password, String algorithm) {

		if (BlankUtils.isBlank(password) || BlankUtils.isBlank(algorithm)) {
			return StringUtils.EMPTY;
		}

		try {

			// 创建随机salt字节数组
			byte[] salt = new byte[12];
			SecureRandom random = new SecureRandom();
			random.nextBytes(salt);

			MessageDigest messageDigest = MessageDigest.getInstance(algorithm);

			messageDigest.update(salt);
			messageDigest.update(password.getBytes());

			// 通过执行诸如填充之类的,最终操作完成哈希计算,并加码返回
			return BASE64EncoderStream.encode(salt).concat(BASE64EncoderStream.encode(messageDigest.digest()));

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

	}

	/**
	 * <p>
	 * 方法用途和描述：将要校验的密码进行哈希计算与原来的信息摘要作比较
	 * </p>
	 * 
	 * @param password
	 *            ：要校验的密码
	 * @param passwordDigest
	 *            ：原密码的信息摘要
	 * @param algorithm
	 *            ：哈希算法
	 * @return 返回校验结果
	 */
	public static boolean verify(String password, String passwordDigest, String algorithm) {

		if (BlankUtils.isBlank(password) || BlankUtils.isBlank(passwordDigest) || BlankUtils.isBlank(algorithm)) {
			return false;
		}

		byte[] saltWithPassword = BASE64DecoderStream.decode(passwordDigest);

		byte[] salt = new byte[12];
		System.arraycopy(saltWithPassword, 0, salt, 0, 12);

		try {
			MessageDigest messageDigest = MessageDigest.getInstance(algorithm);

			messageDigest.update(salt);
			messageDigest.update(password.getBytes());
			byte[] digest = messageDigest.digest();

			byte[] originallyDigest = new byte[saltWithPassword.length - 12];
			System.arraycopy(saltWithPassword, 12, originallyDigest, 0, originallyDigest.length);

			return Arrays.equals(digest, originallyDigest);

		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}

	}

	/**
	 * <p>
	 * 方法用途和描述：将随机盐参合到密码中进行加码
	 * </p>
	 * 
	 * @param password
	 *            ：需要加码的密码
	 * @return 返回加码后的密码
	 */
	public static String encoder(String password) {

		if (BlankUtils.isBlank(password)) {
			return StringUtils.EMPTY;
		}

		byte[] salt = new byte[12];
		SecureRandom random = new SecureRandom();
		random.nextBytes(salt);

		byte[] passBytes = password.getBytes();
		byte[] saltWithPassword = new byte[passBytes.length + 12];

		// 参合随机盐
		System.arraycopy(salt, 0, saltWithPassword, 0, 12);
		System.arraycopy(passBytes, 0, saltWithPassword, 12, passBytes.length);

		return BASE64EncoderStream.encode(saltWithPassword);

	}

	/**
	 * <p>
	 * 方法用途和描述：对参合随机盐的密码解码
	 * </p>
	 * 
	 * @param cipherPassword
	 *            ：加码后的密码
	 * @return 返回解码后的原密码
	 */
	public static String decoder(String cipherPassword) {

		if (BlankUtils.isBlank(cipherPassword)) {
			return StringUtils.EMPTY;
		}

		byte[] saltWithPassword = BASE64DecoderStream.decode(cipherPassword);
		byte[] password = new byte[saltWithPassword.length - 12];

		System.arraycopy(saltWithPassword, 12, password, 0, password.length);

		return new String(password);
	}

	/**
	 * <p>
	 * 方法用途和描述：校验加码的密码
	 * </p>
	 * 
	 * @param password
	 *            ：要校验的密码
	 * @param cipherPassword
	 *            ：加码后的密码
	 * @return 返回校验结果
	 */
	public static boolean validate(String password, String cipherPassword) {

		if (!BlankUtils.isBlank(password)) {
			return password.equals(decoder(cipherPassword)) ? true : false;
		}
		return false;

	}
}
